Editor.Util = {
    isDragging: function () {
        return Editor.STATE.DRAGGER != undefined && Editor.STATE.DRAGGER.getIsActive();
    },
    undo: function () {
        Editor.Util.unselectAll();
        Editor.STATE.CMDSTACK.undo()
    },
    redo: function () {
        Editor.Util.unselectAll();
        Editor.STATE.CMDSTACK.redo()
    },
    prepareAddResource: function () {
        Editor.STATE.ADDSHAPE = Editor.Util.addResource;
        Editor.STATE.ADDDIALOG = 'dialogAddResource';
        Editor.Util.prepareAdd();
    },
    prepareAddLiteral: function () {
        Editor.STATE.ADDSHAPE = Editor.Util.addLiteral;
        Editor.STATE.ADDDIALOG = 'dialogAddLiteral';
        Editor.Util.prepareAdd();
    },
    prepareAddVocabClass: function () {
        Editor.STATE.ADDSHAPE = Editor.Util.addVocabClass;
        Editor.STATE.ADDDIALOG = 'dialogAddVocabClass';
        Editor.Util.prepareAdd();
    },
    prepareAddVocabProperty: function () {
        Editor.STATE.ADDSHAPE = Editor.Util.addVocabProperty;
        Editor.STATE.ADDDIALOG = 'dialogAddVocabProperty';
        Editor.Util.prepareAdd();
    },
    prepareAddVocabIndividual: function () {
        Editor.STATE.ADDSHAPE = Editor.Util.addVocabIndividual;
        Editor.STATE.ADDDIALOG = 'dialogAddVocabIndividual';
        Editor.Util.prepareAdd();
    },
    prepareAdd: function () {
        $('#canvasAdd').addClass('canvas');
        $('#canvasAdd').css("width", "" + Editor.CONFIG.CANVAS_WIDTH);
        $('#canvasAdd').css("height", "" + Editor.CONFIG.CANVAS_HEIGHT);
        Editor.STATE.ISADDSHAPE = true;
    },
    addResource: function (x, y, u) {
        var n1 = new Editor.Models.Namespace();
        n1.init();
        n1.setPrefix('');
        n1.setUri('');
        var r1 = new Editor.Shapes.ResourceConnectable(u);
        r1.setNamespace(n1);
        r1.setName('');
        r1.draw();
        r1.moveTo(x, y);
        Editor.STATE.SHAPES.store(r1.getUuid(), r1);
        return r1;
    },
    addProperty: function (x, y, u, rIni, rEnd) {
        var ns = new Editor.Models.Namespace();
        ns.init();
        var prop = new Editor.Shapes.Property(u, rIni, rEnd);
        prop.setNamespace(ns);
        prop.setName('');
        prop.draw();
        prop.moveTo(x, y);
        Editor.STATE.SHAPES.store(prop.getUuid(), prop);
        var cIni = Editor.Util.addConnection(rIni, prop.getUuid());
        var cEnd = Editor.Util.addConnection(prop.getUuid(), rEnd);
        return {
            'shape': prop,
            'connectionIni': cIni,
            'connectionEnd': cEnd
        };
    },
    addLiteral: function (x, y, u) {
        var l1 = new Editor.Shapes.Literal(u);
        l1.setText('');
        l1.setLang('');
        l1.setDatatype('');
        l1.draw();
        l1.moveTo(x, y);
        Editor.STATE.SHAPES.store(l1.getUuid(), l1);
        return l1;
    },
    addVocabClass: function (x, y, u) {
        var n1 = new Editor.Models.Namespace();
        n1.init();
        n1.setPrefix('');
        n1.setUri('');
        var r1 = new Editor.Shapes.VocabClass(u);
        r1.setNamespace(n1);
        r1.setName('');
        r1.draw();
        r1.moveTo(x, y);
        Editor.STATE.SHAPES.store(r1.getUuid(), r1);
        return r1;
    },
    addVocabProperty: function (x, y, u) {
        var n1 = new Editor.Models.Namespace();
        n1.init();
        n1.setPrefix('');
        n1.setUri('');
        var r1 = new Editor.Shapes.VocabProperty(u);
        r1.setNamespace(n1);
        r1.setName('');
        r1.draw();
        r1.moveTo(x, y);
        Editor.STATE.SHAPES.store(r1.getUuid(), r1);
        return r1;
    },
    addVocabIndividual: function (x, y, u) {
        var n1 = new Editor.Models.Namespace();
        n1.init();
        n1.setPrefix('');
        n1.setUri('');
        var r1 = new Editor.Shapes.VocabIndividual(u);
        r1.setNamespace(n1);
        r1.setName('');
        r1.draw();
        r1.moveTo(x, y);
        Editor.STATE.SHAPES.store(r1.getUuid(), r1);
        return r1;
    },
    addConnection: function (ui, ue, u) {
        var c = new Editor.Connection(ui, ue);
        c.draw();
        Editor.STATE.CONNECTIONS.store(c.getUuid(), c);
        return c;
    },
    unselectAll: function () {
        var arrSelected = Editor.STATE.SELECTED;
        while (arrSelected.length > 0) {
            var shape = arrSelected.pop();
            shape.unselect();
        }
    },
    select: function (shape) {
        Editor.STATE.SELECTED.push(shape);
        shape.select();
    },
    unselect: function (shape) {
        var arrSelected = Editor.STATE.SELECTED;
        var toRemove = -1;
        for (var i = 0; i < arrSelected.length; i++) {
            if (shape.getUuid() == arrSelected[i].getUuid()) {
                toRemove = i;
            }
        }
        if (toRemove >= 0) {
            arrSelected.splice(toRemove, 1);
        }
    },
    toggleLang: function () {
        if (Editor.STATE.LANG.code == 'es') {
            Editor.STATE.LANG = Editor.LANG.EN;
        } else if (Editor.STATE.LANG.code == 'en') {
            Editor.STATE.LANG = Editor.LANG.ES;
        }
        Editor.Init.lang();
    },
    canvasAddClick: function (e) {
        var pos = $("#canvas").position();
        var x = e.clientX - pos.left;
        var y = e.clientY - pos.top;
        if (Editor.CONFIG.GRID_SNAP) {
            x = Math.round(x / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
            y = Math.round(y / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
        }
        var cmd = new JS.Command({
            execute: function () {
                if (this.shape != undefined) {
                    this.shape.draw();
                } else {
                    this.shape = Editor.STATE.ADDSHAPE(x, y);
                    Editor.STATE.SHAPETOUPDATE = this.shape;
                }
            },
            undo: function () {
                this.shape._remove();
            },
            stack: Editor.STATE.CMDSTACK
        });
        cmd.name = 'add shape';
        cmd.execute();
        Editor.STATE.ADDSHAPE = undefined;
        $('#canvasAdd').removeClass('canvas');
        Editor.Keys.unbind();
        $('#' + Editor.STATE.ADDDIALOG).jqm({
            overlay: 40,
            modal: true
        }).jqmShow();
    },
    updateResource: function () {
        var shape = Editor.STATE.SHAPETOUPDATE;
        var newName = $('#name').val();
        var newNamespacePrefix = $('#namespacePrefix').val();
        var newNamespaceUri = $('#namespaceUri').val();
        if (Editor.STATE.ISADDSHAPE) {
            shape.setName(newName);
            shape.getNamespace().setPrefix(newNamespacePrefix);
            shape.getNamespace().setUri(newNamespaceUri);
            shape.updateText();
            Editor.STATE.ISADDSHAPE = false;
            if (shape.getTypeClass() == 'property') {
                var nW = -shape.getWidth() / 2;
                var nH = -shape.getHeight() / 2;
                if (Editor.CONFIG.GRID_SNAP) {
                    nW = Math.round(nW / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                    nH = Math.round(nH / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                }
                shape.translate(nW, nH);
            }
            Editor.Util.showAllLines();
        } else {
            var oldName = shape.getName();
            var oldNamespacePrefix = shape.getNamespace().getPrefix();
            var oldNamespaceUri = shape.getNamespace().getUri();
            var oldWidth = shape.getWidth();
            var cmd = new JS.Command({
                execute: function () {
                    shape.setName(newName);
                    shape.getNamespace().setPrefix(newNamespacePrefix);
                    shape.getNamespace().setUri(newNamespaceUri);
                    shape.updateText();
                },
                undo: function () {
                    shape.setName(oldName);
                    shape.getNamespace().setPrefix(oldNamespacePrefix);
                    shape.getNamespace().setUri(oldNamespaceUri);
                    shape.updateText();
                    shape._resize(oldWidth - shape.getWidth(), 0);
                },
                stack: Editor.STATE.CMDSTACK
            });
            cmd.name = 'update resource';
            cmd.execute();
        }
        Editor.Keys.bind();
        $('#dialogAddResource').jqmHide();
    },
    cancelUpdateResource: function () {
        if (Editor.STATE.ISADDSHAPE) {
            // tricky
            Editor.Util.undo();
            Editor.STATE.ISADDSHAPE = false;
        }
        Editor.Keys.bind();
        $('#dialogAddResource').jqmHide();
    },
    updateLiteral: function () {
        var shape = Editor.STATE.SHAPETOUPDATE;
        var newText = $('#text').val();
        var newLang = $('#lang').val();
        var newDatatype = $('#datatype').val();
        if (Editor.STATE.ISADDSHAPE) {
            shape.setText(newText);
            shape.setLang(newLang);
            shape.setDatatype(newDatatype);
            shape.updateText();
            Editor.STATE.ISADDSHAPE = false;
        } else {
            var oldText = shape.getText();
            var oldLang = shape.getLang();
            var oldDatatype = shape.getDatatype();
            var oldWidth = shape.getWidth();
            var oldHeight = shape.getHeight();
            var cmd = new JS.Command({
                execute: function () {
                    shape.setText(newText);
                    shape.setLang(newLang);
                    shape.setDatatype(newDatatype);
                    shape.updateText();
                },
                undo: function () {
                    shape.setText(oldText);
                    shape.setLang(oldLang);
                    shape.setDatatype(oldDatatype);
                    shape.updateText();
                    shape._resize(oldWidth - shape.getWidth(), oldHeight - shape.getHeight());
                },
                stack: Editor.STATE.CMDSTACK
            });
            cmd.name = 'update literal';
            cmd.execute();
        }
        Editor.Keys.bind();
        $('#dialogAddLiteral').jqmHide();
    },
    cancelUpdateLiteral: function () {
        if (Editor.STATE.ISADDSHAPE) {
            // tricky
            Editor.Util.undo();
            Editor.STATE.ISADDSHAPE = false;
        }
        Editor.Keys.bind();
        $('#dialogAddLiteral').jqmHide();
    },


    updateVocabClass: function () {
        var shape = Editor.STATE.SHAPETOUPDATE;
        var newName = $('#vc_name').val();
        var newNamespacePrefix = $('#vc_namespacePrefix').val();
        var newNamespaceUri = $('#vc_namespaceUri').val();
        if (Editor.STATE.ISADDSHAPE) {
            shape.setName(newName);
            shape.getNamespace().setPrefix(newNamespacePrefix);
            shape.getNamespace().setUri(newNamespaceUri);
            shape.updateText();
            Editor.STATE.ISADDSHAPE = false;
            if (shape.getTypeClass() == 'property') {
                var nW = -shape.getWidth() / 2;
                var nH = -shape.getHeight() / 2;
                if (Editor.CONFIG.GRID_SNAP) {
                    nW = Math.round(nW / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                    nH = Math.round(nH / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                }
                shape.translate(nW, nH);
            }
        } else {
            var oldName = shape.getName();
            var oldNamespacePrefix = shape.getNamespace().getPrefix();
            var oldNamespaceUri = shape.getNamespace().getUri();
            var oldWidth = shape.getWidth();
            var cmd = new JS.Command({
                execute: function () {
                    shape.setName(newName);
                    shape.getNamespace().setPrefix(newNamespacePrefix);
                    shape.getNamespace().setUri(newNamespaceUri);
                    shape.updateText();
                },
                undo: function () {
                    shape.setName(oldName);
                    shape.getNamespace().setPrefix(oldNamespacePrefix);
                    shape.getNamespace().setUri(oldNamespaceUri);
                    shape.updateText();
                    shape._resize(oldWidth - shape.getWidth(), 0);
                },
                stack: Editor.STATE.CMDSTACK
            });
            cmd.name = 'update resource';
            cmd.execute();
        }
        Editor.Keys.bind();
        $('#dialogAddVocabClass').jqmHide();
    },
    updateVocabProperty: function () {
        var shape = Editor.STATE.SHAPETOUPDATE;
        var newName = $('#vp_name').val();
        var newNamespacePrefix = $('#vp_namespacePrefix').val();
        var newNamespaceUri = $('#vp_namespaceUri').val();
        if (Editor.STATE.ISADDSHAPE) {
            shape.setName(newName);
            shape.getNamespace().setPrefix(newNamespacePrefix);
            shape.getNamespace().setUri(newNamespaceUri);
            shape.updateText();
            Editor.STATE.ISADDSHAPE = false;
            if (shape.getTypeClass() == 'property') {
                var nW = -shape.getWidth() / 2;
                var nH = -shape.getHeight() / 2;
                if (Editor.CONFIG.GRID_SNAP) {
                    nW = Math.round(nW / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                    nH = Math.round(nH / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                }
                shape.translate(nW, nH);
            }
        } else {
            var oldName = shape.getName();
            var oldNamespacePrefix = shape.getNamespace().getPrefix();
            var oldNamespaceUri = shape.getNamespace().getUri();
            var oldWidth = shape.getWidth();
            var cmd = new JS.Command({
                execute: function () {
                    shape.setName(newName);
                    shape.getNamespace().setPrefix(newNamespacePrefix);
                    shape.getNamespace().setUri(newNamespaceUri);
                    shape.updateText();
                },
                undo: function () {
                    shape.setName(oldName);
                    shape.getNamespace().setPrefix(oldNamespacePrefix);
                    shape.getNamespace().setUri(oldNamespaceUri);
                    shape.updateText();
                    shape._resize(oldWidth - shape.getWidth(), 0);
                },
                stack: Editor.STATE.CMDSTACK
            });
            cmd.name = 'update resource';
            cmd.execute();
        }
        Editor.Keys.bind();
        $('#dialogAddVocabProperty').jqmHide();
    },
    updateVocabIndividual: function () {
        var shape = Editor.STATE.SHAPETOUPDATE;
        var newName = $('#vi_name').val();
        var newNamespacePrefix = $('#vi_namespacePrefix').val();
        var newNamespaceUri = $('#vi_namespaceUri').val();
        if (Editor.STATE.ISADDSHAPE) {
            shape.setName(newName);
            shape.getNamespace().setPrefix(newNamespacePrefix);
            shape.getNamespace().setUri(newNamespaceUri);
            shape.updateText();
            Editor.STATE.ISADDSHAPE = false;
            if (shape.getTypeClass() == 'property') {
                var nW = -shape.getWidth() / 2;
                var nH = -shape.getHeight() / 2;
                if (Editor.CONFIG.GRID_SNAP) {
                    nW = Math.round(nW / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                    nH = Math.round(nH / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
                }
                shape.translate(nW, nH);
            }
        } else {
            var oldName = shape.getName();
            var oldNamespacePrefix = shape.getNamespace().getPrefix();
            var oldNamespaceUri = shape.getNamespace().getUri();
            var oldWidth = shape.getWidth();
            var cmd = new JS.Command({
                execute: function () {
                    shape.setName(newName);
                    shape.getNamespace().setPrefix(newNamespacePrefix);
                    shape.getNamespace().setUri(newNamespaceUri);
                    shape.updateText();
                },
                undo: function () {
                    shape.setName(oldName);
                    shape.getNamespace().setPrefix(oldNamespacePrefix);
                    shape.getNamespace().setUri(oldNamespaceUri);
                    shape.updateText();
                    shape._resize(oldWidth - shape.getWidth(), 0);
                },
                stack: Editor.STATE.CMDSTACK
            });
            cmd.name = 'update resource';
            cmd.execute();
        }
        Editor.Keys.bind();
        $('#dialogAddVocabIndividual').jqmHide();
    },
    cancelUpdateVocabClass: function () {
        if (Editor.STATE.ISADDSHAPE) {
            // tricky
            Editor.Util.undo();
            Editor.STATE.ISADDSHAPE = false;
        }
        Editor.Keys.bind();
        $('#dialogAddVocabClass').jqmHide();
    },
    cancelUpdateVocabProperty: function () {
        if (Editor.STATE.ISADDSHAPE) {
            // tricky
            Editor.Util.undo();
            Editor.STATE.ISADDSHAPE = false;
        }
        Editor.Keys.bind();
        $('#dialogAddVocabProperty').jqmHide();
    },
    cancelUpdateVocabIndividual: function () {
        if (Editor.STATE.ISADDSHAPE) {
            // tricky
            Editor.Util.undo();
            Editor.STATE.ISADDSHAPE = false;
        }
        Editor.Keys.bind();
        $('#dialogAddVocabIndividual').jqmHide();
    },


    moveShapes: function (dir) {
        Editor.Util.hideAllLines();
        var step = 1;
        var dx = 0;
        var dy = 0;
        if (Editor.CONFIG.GRID_SNAP) {
            step = Editor.CONFIG.GRID_SIZE;
        }
        switch (dir) {
        case 'left':
            dx = step * -1;
            break;
        case 'right':
            dx = step;
            break;
        case 'up':
            dy = step * -1;
            break;
        case 'down':
            dy = step;
            break;
        }
        var arrSelected = Editor.STATE.SELECTED;
        var arr = new Array();
        for (var i = 0; i < arrSelected.length; i++) {
            arr.push(arrSelected[i]);
        }
        var cmd = new JS.Command({
            execute: function () {
                for (var i = 0; i < arr.length; i++) {
                    arr[i].translate(dx, dy);
                }
                Editor.Util.showAllLines();
            },
            undo: function () {
                for (var i = 0; i < arr.length; i++) {
                    arr[i].translate(dx * -1, dy * -1);
                }
                Editor.Util.showAllLines();
            },
            stack: Editor.STATE.CMDSTACK
        });
        cmd.name = 'move shapes';
        cmd.execute();
    },
    removeShapes: function () {
        var arrSelected = Editor.STATE.SELECTED;

        var arr = new Array();
        for (var i = 0; i < arrSelected.length; i++) {
            arr.push(arrSelected[i]);
        }

        var arrProperties = new Array();
        for (var i = 0; i < arrSelected.length; i++) {
            var s = arrSelected[i];
            if (s.getTypeClass() == "resourceConnectable" || s.getTypeClass() == "literal" || s.getTypeClass() == "vocabIndividual") {
                var aProps = s.getInProperties();
                for (var j = 0; j < aProps.length; j++) {
                    var p = Editor.STATE.SHAPES.get(aProps[j]);
                    if (!p.getIsDeleted()) {
                        arrProperties.push(aProps[j]);
                    }
                }
            }
        }

        var arrVocProps = new Array();
        for (var i = 0; i < arrSelected.length; i++) {
            var s = arrSelected[i];
            if (s.getTypeClass() == "vocabClass") {
                var aProps = s.getVocProps();
                for (var j = 0; j < aProps.length; j++) {
                    var p = Editor.STATE.SHAPES.get(aProps[j]);
                    if (!p.getIsDeleted()) {
                        arrVocProps.push(aProps[j]);
                    }
                }
            }
        }

        var arrConnections = new Array();
        var cmd = new JS.Command({
            execute: function () {
                for (var j = 0; j < arrProperties.length; j++) {
                    var p = Editor.STATE.SHAPES.get(arrProperties[j]);
                    if (!p.getIsDeleted()) {
                        Editor.Util.removeConnections(p.getUuid(), arrConnections);
                        p._remove();
                    }
                }
                for (var j = 0; j < arrVocProps.length; j++) {
                    var p = Editor.STATE.SHAPES.get(arrVocProps[j]);
                    if (!p.getIsDeleted()) {
                        Editor.Util.removeConnections(p.getUuid(), arrConnections);
                        p._remove();
                    }
                }
                for (var i = 0; i < arr.length; i++) {
                    Editor.Util.removeConnections(arr[i].getUuid(), arrConnections);
                    arr[i]._remove()
                }
            },
            undo: function () {
                for (var i = 0; i < arr.length; i++) {
                    arr[i].draw();
                }
                for (var j = 0; j < arrProperties.length; j++) {
                    var p = Editor.STATE.SHAPES.get(arrProperties[j]);
                    if (p.getIsDeleted()) {
                        p.draw();
                    }
                }
                for (var j = 0; j < arrVocProps.length; j++) {
                    var p = Editor.STATE.SHAPES.get(arrVocProps[j]);
                    if (p.getIsDeleted()) {
                        p.draw();
                    }
                }
                Editor.Util.unremoveConnections(arrConnections);
            },
            stack: Editor.STATE.CMDSTACK
        });
        cmd.name = 'remove shapes';
        cmd.execute();
    },
    addObject: function (obj) {
        var s;
        var dx = 0;
        var dy = 0;
        var bbox;
        if (obj.type == 'resource') {
            bbox = obj.resource.shape.bbox;
            s = Editor.Util.addResource(bbox.x, bbox.y, obj.resource.shape.uuid);
        } else if (obj.type == 'literal') {
            bbox = obj.shape.bbox;
            s = Editor.Util.addLiteral(bbox.x, bbox.y, obj.shape.uuid);
            s.setText(obj.text);
            if (obj.lang) {
                s.setLang(obj.lang)
            };
            if (obj.datatype) {
                s.setDatatype(obj.datatype)
            };
        } else if (obj.type == 'property') {
            bbox = obj.resource.shape.bbox;
            var tmp = Editor.Util.addProperty(bbox.x, bbox.y, obj.resource.shape.uuid, obj.uuidIni, obj.uuidEnd);
            s = tmp.shape;
        } else if (obj.type == 'vocabClass') {
            bbox = obj.resource.shape.bbox;
            s = Editor.Util.addVocabClass(bbox.x, bbox.y, obj.resource.shape.uuid);
            if (obj.vocProps) {
                var arr = obj.vocProps.split(' ');
                for (var i = 0; i < arr.length - 1; i++) {
                    s.addVocabPropertie(arr[i]);
                }
                s.updateVocabProperties();
            }
        } else if (obj.type == 'vocabProperty') {
            bbox = obj.resource.shape.bbox;
            s = Editor.Util.addVocabProperty(bbox.x, bbox.y, obj.resource.shape.uuid);
            if (obj.domain) {
                s.setDomain(obj.domain);
            }
            if (obj.range) {
                s.setRange(obj.range);
            }
        } else if (obj.type == 'vocabIndividual') {
            bbox = obj.resource.shape.bbox;
            s = Editor.Util.addVocabIndividual(bbox.x, bbox.y, obj.resource.shape.uuid);
        } else if (obj.type == 'connection') {
            s = Editor.Util.addConnection(obj.uuidIni, obj.uuidEnd, obj.uuid);
            //if (s.getType() == 'range' || s.getType() == 'subProperty') {
            //    s.remove();
            //}
        }

        if (obj.type != 'connection') {
            if (obj.type != 'literal') {
                var ele = obj.resource.element;
                s.setName(ele.name);
                var ns = ele.namespace;
                if (ns) {
                    if (ns.prefix) {
                        s.getNamespace().setPrefix(ns.prefix)
                    }
                    if (ns.uri) {
                        s.getNamespace().setUri(ns.uri)
                    }
                }
            }
            s.updateText();
            if (bbox.width) {
                dx = bbox.width - s.getWidth()
            }
            if (bbox.height) {
                dy = bbox.height - s.getHeight()
            }
            s._resize(dx, dy);
        }
    },
    hideAllLines: function () {
        Editor.STATE.CONNECTIONS.forEach(function (pair) {
            var connection = pair.value;
            if (!connection.getIsDeleted()) {
                connection.hide();
            }
        });
    },
    showAllLines: function () {
        Editor.STATE.CONNECTIONS.forEach(function (pair) {
            var connection = pair.value;
            if (!connection.getIsDeleted()) {
                connection.draw();
                connection.show();
            }
        });
    },
    drawObjects: function (arrObjects) {
        for (i = 0; i < arrObjects.length; i++) {
            obj = arrObjects[i];
            if (obj.type != 'property' && obj.type != 'connection' && obj.type != 'vocabClass') {
                Editor.Util.addObject(obj);
            }
        }
        for (i = 0; i < arrObjects.length; i++) {
            obj = arrObjects[i];
            if (obj.type == 'vocabClass') {
                Editor.Util.addObject(obj);
            }
        }
        for (i = 0; i < arrObjects.length; i++) {
            obj = arrObjects[i];
            if (obj.type == 'property') {
                Editor.Util.addObject(obj);
            }
        }
        for (i = 0; i < arrObjects.length; i++) {
            obj = arrObjects[i];
            if (obj.type == 'connection') {
                Editor.Util.addObject(obj);
            }
        }
        Editor.Util.showAllLines();
    },
    prepareOptions: function () {
        Editor.Keys.unbind();
        $('#dialogOptions').jqm({
            overlay: 40,
            modal: true
        }).jqmShow();
        $('#gridSize').val(Editor.CONFIG.GRID_SIZE);
        $('#canvasWidth').val(Editor.CONFIG.CANVAS_WIDTH);
        $('#canvasHeight').val(Editor.CONFIG.CANVAS_HEIGHT);
        if (Editor.CONFIG.GRID_SHOW) {
            $('#gridShowYes').attr('checked', true);
            $('#gridShowNo').attr('checked', false);
        } else {
            $('#gridShowYes').attr('checked', false);
            $('#gridShowNo').attr('checked', true);
        }
        if (Editor.CONFIG.GRID_SNAP) {
            $('#gridSnapYes').attr('checked', true);
            $('#gridSnapNo').attr('checked', false);
        } else {
            $('#gridSnapYes').attr('checked', false);
            $('#gridSnapNo').attr('checked', true);
        }

    },
    updateOptions: function () {
        Editor.CONFIG.GRID_SIZE = parseInt($('#gridSize').val());
        Editor.CONFIG.CANVAS_WIDTH = $('#canvasWidth').val();
        Editor.CONFIG.CANVAS_HEIGHT = $('#canvasHeight').val();
        Editor.STATE.CANVAS.setSize(Editor.CONFIG.CANVAS_WIDTH, Editor.CONFIG.CANVAS_HEIGHT);
        Editor.STATE.BACKGROUND.attr({
            width: Editor.CONFIG.CANVAS_WIDTH,
            height: Editor.CONFIG.CANVAS_HEIGHT
        });
        $('#dialogOptions').jqmHide();
        Editor.Keys.bind();
    },
    closeOptions: function () {
        $('#dialogOptions').jqmHide();
        Editor.Keys.bind();
    },
    // http://www.netlobo.com/url_query_string_javascript.html
    gup: function (name) {
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        var regexS = "[\\?&]" + name + "=([^&#]*)";
        var regex = new RegExp(regexS);
        var results = regex.exec(window.location.href);
        if (results == null) return "";
        else return results[1];
    },

    about: function () {
        $('#dialogAbout-' + Editor.STATE.LANG.code).jqm().jqmShow();
    },
    closeAbout: function () {
        $('#dialogAbout-' + Editor.STATE.LANG.code).jqmHide();
    },
    //do the same thing as the Perl "keys" subroutine
    getKeys: function (o) {
        var accumulator = [];
        for (var propertyName in o) {
            accumulator.push(propertyName);
        }
        return accumulator;
    },
    //get values instead of keys
    getValues: function (o) {
        var accumulator = [];
        for (var propertyName in o) {
            accumulator.push(o[propertyName]);
        }
        return accumulator;
    },
    // from google closure library, base.js, goog.inherits
    // http://code.google.com/closure/library
    inherits: function (childCtor, parentCtor) { /** @constructor */

        function tempCtor() {};
        tempCtor.prototype = parentCtor.prototype;
        childCtor.superClass_ = parentCtor.prototype;
        childCtor.prototype = new tempCtor();
        childCtor.prototype.constructor = childCtor;
    },

    removeConnections: function (uuidShape, arr) {
        Editor.STATE.CONNECTIONS.forEach(function (pair) {
            var connection = pair.value;
            if (connection.hasShape(uuidShape) && !connection.getIsDeleted()) {
                arr.push(connection.getUuid());
                connection.remove();
            }
        });
    },
    unremoveConnections: function (arr) {
        for (var i = 0; i < arr.length; i++) {
            Editor.STATE.CONNECTIONS.get(arr[i]).unremove();
        }
    },
    addSubscribeToCmdStack: function (cmdstack) {
        cmdstack.subscribe(function (stack) {
            var list = document.getElementById('commands'),
                str = '';
            stack.forEach(function (command, i) {
                var color = (i >= stack.pointer) ? '#999' : '#000';
                str += '<div style="color: ' + color + ';"> &gt; ' + command.name + '</div>';
            });
            list.innerHTML = str;
            list.scrollTop = list.scrollHeight;
        });
    },
    updateNamespaces: function () {
        var list = document.getElementById('namespaces'),
            str = '';
        var namespaces = new JS.Hash();
        Editor.STATE.SHAPES.forEach(function (pair) {
            shape = pair.value;
            if (!shape.getIsDeleted()) {
                if (shape.getNamespace) {
                    namespaces.store(shape.getNamespace().getPrefix(), shape.getNamespace().getUri());
                }
            }
        });
        namespaces.forEach(function (pair) {
            if (pair.key) {
                str += '<div onClick="Editor.Util.pulseNamespace(\'' + pair.key + '\')"> &gt; ' + pair.key + ' = ' + pair.value + '</div>';
            }
        });
        delete namespaces;
        list.innerHTML = str;
    },

    toggleCmdHistoryPanel: function () {
        $('#panelNamespaces').hide();
        $('#panelCommands').toggle();
    },
    toggleNamespacesPanel: function () {
        $('#panelCommands').hide();
        Editor.Util.updateNamespaces();
        $('#panelNamespaces').toggle();
    },
    exportToPng: function () {
        if (!$('#export_canvas').length) {
            $('<canvas>', {
                id: 'export_canvas'
            }).hide().appendTo('body');
        }
        var c = $('#export_canvas')[0];
        c.width = Editor.CONFIG.CANVAS_WIDTH;
        c.height = Editor.CONFIG.CANVAS_HEIGHT;
        //console.log($('#canvas').html() );
        canvg(c, $('#canvas').html());
        window.open(c.toDataURL('image/png'));
    },
    keyCanvasUp: function (e) {
        if (e.which == 13) {
            Editor.CONFIG.CANVAS_WIDTH = $('#textCanvasWidthUp').val();
            Editor.CONFIG.CANVAS_HEIGHT = $('#textCanvasHeightUp').val();
            Editor.STATE.CANVAS.setSize(Editor.CONFIG.CANVAS_WIDTH, Editor.CONFIG.CANVAS_HEIGHT);
            Editor.STATE.DRAGGERCANVAS.redraw();
            e.preventDefault();
        }
        return false;
    },
    pulseNamespace: function (ns) {
        Editor.STATE.SHAPES.forEach(function (pair) {
            var shape = pair.value;
            if (!shape.getIsDeleted()) {
                if (shape.getNamespace) {
                    if (shape.getNamespace().getPrefix() == ns) {
                        shape.animateFillColor('#0f0');
                    }
                }
            }
        });
    },

}
